<template>
  <el-form ref="formRef" v-bind="$attrs" :model="formModel">
    <el-row :gutter="gutter">
        <template v-for="(item) in formList">
          <el-col
            v-if="!item.hidden"
            :key="item.prop"
            :xl="item.itemSpan || itemSpan"
            :md="item.itemSpan || 12"
            :xs="24"
          >
            <el-form-item
              class="base-form-item"
              :label="`${item.label} :`"
              :prop="item.prop"
              v-bind="getFormItemProps(item)"
            >
              <slot v-if="item.valueType === 'custom'" :name="item.prop" :model="formModel" :item="item">
              </slot>
              <FormControls
                v-else
                :valueType="item.valueType"
                :options="item.options ?? []"
                v-bind="item.fieldProps"
                :on="item.on"
                v-model="formModel[item.prop]"
              />
            </el-form-item>
          </el-col>
        </template>
    </el-row>
  </el-form>
</template>

<script lang="ts">
export default {
  name: "BaseForm",
  inheritAttrs: false,
}
</script>
<script setup lang="ts">
import type { FormInstance } from 'element-plus';

interface FormProps {
  formList: any[];
  model: any;
  gutter?: number;
  itemSpan?: number;
}

// 默认值
const props = withDefaults(defineProps<FormProps>(), {
  formList: () => ([]),
  model: () => ({}),
  gutter: 16,
  itemSpan: 12,
});

const formModel = ref<any>({})

const initForm = () => {
  const initData = props.formList.reduce((cur, next) => {
    const { prop, defaultValue } = next;
    if (prop) {
      cur[prop] = defaultValue || (next.valueType === 'input-number' ? 0 : '');
    }
    return cur
  }, {})
  formModel.value = initData
}

watch(
  () => props.model,
  (newValue) => {
    formModel.value = newValue
  },
  {
    deep: true,
    immediate: true
  }
)

const setData = (data: any) => {
  formModel.value = data
}

const getData = () => {
  return formModel.value
}

const resetData = () => {
  initForm()
}

const getFormItemProps = (item: any) => {
  const { rules, formItemProps } = item
  return Array.isArray(rules) ? { rules, ...formItemProps } : formItemProps
}

const formRef = ref<FormInstance>()

const validate = (...args: any) => {
  return formRef.value?.validate(...args);
}

const resetFields = (...args: any) => {
  formRef.value?.resetFields(...args);
  resetData()
}

// 暴露给父组件的参数和方法(外部需要什么，都可以从这里暴露出去)
defineExpose({
  validate,
  resetFields,
  setData,
  getData,
  resetData,
});
</script>

<style lang="scss" scoped>
.base-form-item {
  display: flex;

  ::v-deep {
    >.el-form-item__label {
      white-space: pre;
    }

    >.el-form-item__content {
      width: 1px;
      flex: 1;
      display: flex;
      align-items: center;
      margin-left: 0 !important;

      > {
        .el-input {
          flex: 1;
        }

        .el-select {
          flex: 1;
        }

        .el-cascader {
          flex: 1;
        }
      }
    }
  }
}
</style>
